package com.liuqi.knet.remoting.transport.dispatcher.handler;

import com.liuqi.knet.remoting.Channel;
import com.liuqi.knet.remoting.ChannelHandler;
import com.liuqi.knet.remoting.ClientConfig;
import com.liuqi.knet.remoting.RemotingException;
import com.liuqi.knet.remoting.exchange.Event;
import com.liuqi.knet.remoting.transport.AbstractChannelHandlerDelegate;
import com.liuqi.loggers.api.Logger;
import com.liuqi.loggers.facade.LoggersFacade;

/**
 * 客户端校验,
 * 1. 定时发送心跳
 *
 * @author liuqi
 * @date 2025/3/6 14:14
 **/
public class ClientVerifyHandler extends AbstractChannelHandlerDelegate {

    private static final Logger logger = LoggersFacade.getLogger(ClientVerifyHandler.class);

    private ClientConfig config;

    /**
     * 发送心跳间隔
     */
    private int heartbeatSleep;

    /**
     * 客户端
     */
    private volatile Channel channel;

    /**
     * 定时发送心跳的线程
     */
    private Thread heartbeatThread;

    /**
     * 是否开启定时发送心跳
     */
    private volatile boolean enableHeartbeat;

    public ClientVerifyHandler(ChannelHandler handler, ClientConfig config) {
        super(handler);
        this.config = config;
        this.heartbeatSleep = config.getHeartbeatTimeout() / 10 * 7;

        if (this.config.isEnableHeartbeat()) {
            logger.info("是否对客户端定时检测心跳[{}], 心跳间隔[{}]", true, this.config.getHeartbeatTimeout());
            enableHeartbeat = true;
        }
    }

    @Override
    public void connected(Channel channel) throws RemotingException {
        super.connected(channel);

        this.channel = channel;
        if (enableHeartbeat) {
            heartbeatThread = new Thread(new HeartbeatTimingSend(), "knet-client-heartbeat");
            heartbeatThread.setDaemon(true);
            heartbeatThread.start();
        }
    }

    @Override
    public void disconnected(Channel channel) throws RemotingException {
        super.disconnected(channel);

        this.channel = null;
        heartbeatThread.interrupt();
    }

    @Override
    public void caught(Channel channel, Throwable exception) throws RemotingException {
        super.caught(channel, exception);

        this.channel = null;
        heartbeatThread.interrupt();
    }

    private class HeartbeatTimingSend implements Runnable {
        @Override
        public void run() {
            logger.info("启动定时发送心跳的线程, 每间隔[{}]ms, 所有客户端向服务端发送心跳. ", heartbeatSleep);
            while (true && !heartbeatThread.isInterrupted()) {
                try {
                    if (channel != null && channel.isActive()) {
                        try {
                            logger.info("客户端: [{}], 发送心跳. ", channel);
                            channel.send(new Event(Event.Type.HEARTBEAT));
                        } catch (RemotingException t){
                            logger.info("客户端: " + channel + ", 发送心跳失败. ", t);
                        }
                    }
                    Thread.sleep(heartbeatSleep);
                } catch (Throwable t) {
                }
            }
        }
    }

}
